home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / misc / sci / RARS_Amiga_2.lha / RARS / draw.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-31  |  14.1 KB  |  384 lines

  1. // DRAW.CPP - the system-independent graphics portion of RARS 0.39
  2. // (was GRAPHICS.CPP) - by Mitchell E. Timin, State College, PA
  3. // See GI.H, CAR.H & TRACK.H for class and structure declarations.
  4. // This version is for Borland C++, version 3.1, and is for DOS.
  5. // This is part of version 0.39 of RARS (Robot Auto Racing Simulation).
  6. // GI.CPP is the system-dependent graphics portion of RARS.
  7. // ver. 0.1 release January 12, 1995
  8. // ver. 0.2 1/23/95
  9. // ver. 0.3 2/7/95
  10. // ver. 0.39 3/6/95 
  11.  
  12. /*
  13.  * Modifications made:
  14.  *
  15.  * - l. 143 : Symbol 'errorcode' was not used and has been removed.
  16.  */
  17.  
  18. #include <conio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include "car.h"
  23. #include "track.h"
  24.  
  25. static double finish_x, finish_y;    // These four variables are used to locate
  26. static double finish_y_in, finish_y_out;    // the finish line on the screen.
  27. static double spacing;             // see leaders()
  28.  
  29. extern Car* pcar[];      // array of pointers to the various cars
  30. extern int done_count;   // how many cars have finished the race
  31. extern int lap_count;    // how many laps is this race?
  32. extern int car_count;    // how many cars in the race
  33. extern double length;    // total lenth of track (average of inner and outer rails)
  34. extern char* namptr[];   // array of pointers to their name strings
  35. extern int* order;       // will point to array of positions
  36. extern double CHR_HGT;          // height in feet of row of text
  37. extern int no_display;
  38.  
  39. int round(double given)  // convert double to int by rounding
  40. {
  41.    if(given > 0.0)
  42.       return int(given + .5);
  43.    else
  44.       return int(given - .5);
  45. }
  46.  
  47. // Convert input into an ASCII string with two decimal digits.
  48. void make_dec_string(char* out,         // pointer to destination string
  49.                      double input)      // value to be converted
  50. {
  51.    long int value;
  52.    char intpart[5], decpart[4];
  53.  
  54.    value = (long int)(100.0 * input + .5);
  55.    itoa(int(value / 100), intpart, 10);
  56.    itoa(int(value % 100), decpart, 10);
  57.    if(decpart[1] == '\0') { // we might have to stick in a leading zero:
  58.       decpart[2] = '\0';
  59.       decpart[1] = decpart[0];
  60.       decpart[0] = '0';
  61.    }
  62.    strcpy(out, intpart);
  63.    strcat(out, ".");
  64.    strcat(out, decpart);
  65. }
  66.  
  67. // Assemble a string for the average speed of car i.  (goes to char* out)
  68. void get_avg_spd(int i, char* out)
  69. {
  70.     make_dec_string(out, pcar[i]->speed_avg * MPH_FPS);
  71. }
  72.  
  73. // Assemble a string for the maximum speed of car i.  (goes to char* out)
  74. void get_max_spd(int i, char* out)
  75. {
  76.     make_dec_string(out, pcar[i]->speed_max * MPH_FPS);
  77. }
  78.  
  79. /* new routine: draw_arc() routine that uses draw_line() to draw the arc */
  80. #define LINESEG_LENGTH 10        /* this constant can be used to tweak the precision */
  81. void draw_arc(double radius, double center_x, double center_y, double start_angle, double length)
  82. {
  83.     double a;
  84.     double stepsize;
  85.     double x1, y1, x2, y2;
  86.  
  87.     /* convert a right turn so it is consistent with the left turn */
  88.     if (radius < 0.0)
  89.     {
  90.         radius = -radius;
  91.  
  92.         start_angle = start_angle - length - PI;
  93.         while (start_angle < 0.0)
  94.         {
  95.             start_angle += (2 * PI);
  96.         }
  97.     }
  98.  
  99.     /* calculate the starting point */
  100.     x1 = center_x + radius * sin(start_angle);
  101.     y1 = center_y - radius * cos(start_angle);
  102.  
  103.     /* determine the step size */
  104.     stepsize = LINESEG_LENGTH * (1.0 / (radius * SCALE));
  105.  
  106.     /* draw lines over the length from there, adapting the number of steps to the length */
  107.     for (a = stepsize; a < length; a += stepsize)
  108.     {
  109.         /* calculate the end point of this line */
  110.         x2 = center_x + radius * sin(start_angle + a);
  111.         y2 = center_y - radius * cos(start_angle + a);
  112.  
  113.         /* draw the line */
  114.         draw_line(x1, y1, x2, y2);
  115.  
  116.         /* make the end point the new starting point for the next line */
  117.         x1 = x2;
  118.         y1 = y2;
  119.     }
  120.  
  121.     /* calculate the end point of the arc */
  122.     x2 = center_x + radius * sin(start_angle + length);
  123.     y2 = center_y - radius * cos(start_angle + length);
  124.  
  125.     /* draw the last line */
  126.     draw_line(x1, y1, x2, y2);
  127. }
  128.  
  129. // Draws the path specified by the segment array and starting
  130. // conditions which are given as parameters.  Also, fills in the
  131. // un-initialized portions of the segment array.  Returns the length.
  132. double drawpath(double xstart,      // coordinates of starting point
  133.                 double ystart,
  134.                 double alfstart,    // starting tangent angle
  135.                 segment *track)     // pointer to structure that defines path
  136. {
  137.    double length = 0;          // to accumulate total length of path
  138.    double cenx, ceny;          // center of circle arc
  139.    double radius;              // radius of circle arc (negative == rt. turn)
  140.    double x, y, alf;           // position and direction of start of segment
  141.    double newx, newy, newalf;  // and the one after that  (alf in radians)
  142.    int i;
  143.  
  144.    x = xstart;  y = ystart;   // store starting point & direction
  145.    alf = alfstart;
  146.  
  147.    for(i=0; i < NSEG; i++) {                 // for each segment:
  148.       radius = track[i].radius;
  149.       if(radius == 0.0) {                   // is this a straightaway?
  150.          length += track[i].length;
  151.          newx = x + track[i].length * cos(alf);      // find end coordinates
  152.          newy = y + track[i].length * sin(alf);
  153.          track[i].end_x = newx;   track[i].end_y = newy;    // fill in these
  154.          track[i].beg_x = x;      track[i].beg_y = y;       // empty slots in
  155.          track[i].beg_ang = track[i].end_ang = alf;         // the track array
  156.          newalf = alf;                                // direction won't change
  157.          if(!no_display)
  158.             draw_line(x, y, newx, newy);                // draw the straight line
  159.          if(i == 0)      {      // find pixel locations of start/finish line:
  160.               finish_y = newy;   // assume straightaway parallel to x-axis
  161.               finish_x = x + FINISH * length;
  162.          }
  163.       }
  164.       else if(radius > 0.0) {
  165.          length += radius * track[i].length;
  166.          cenx = x - radius * sin(alf);  // compute center location:
  167.          ceny = y + radius * cos(alf);
  168.          track[i].cen_x = cenx;   track[i].cen_y = ceny;  // fill empty slots
  169.          track[i].beg_ang = alf;
  170.          newalf = alf + track[i].length;           // compute new direction
  171.          track[i].end_ang = newalf;                // fill this empty slot
  172.          newx = cenx + radius * sin(newalf);   // location of end
  173.          newy = ceny - radius * cos(newalf);
  174.          track[i].end_x = newx;   track[i].end_y = newy;  // fill in these
  175.          track[i].beg_x = x;      track[i].beg_y = y;     // empty slots
  176.          if(!no_display)
  177.             draw_arc(radius, cenx, ceny, alf, track[i].length);   // draw the arc
  178.       }
  179.       else {
  180.          length -= radius * track[i].length;
  181.          cenx = x - radius * sin(alf);  // compute center location:
  182.          ceny = y + radius * cos(alf);
  183.          track[i].cen_x = cenx;   track[i].cen_y = ceny;  // fill empty slots
  184.          track[i].beg_ang = alf;
  185.          newalf = alf - track[i].length;           // compute new direction
  186.          track[i].end_ang = newalf;                // fill this empty slot
  187.          newx = cenx + radius * sin(newalf);   // location of end
  188.          newy = ceny - radius * cos(newalf);
  189.          track[i].end_x = newx;   track[i].end_y = newy;  // fill in these
  190.          track[i].beg_x = x;      track[i].beg_y = y;     // empty slots
  191.          if(!no_display)
  192.             draw_arc(radius, cenx, ceny, alf, track[i].length);   // draw the arc
  193.       }
  194.       x = newx;                     // repeat with new position and direction:
  195.       y = newy;
  196.       alf = newalf;
  197.    }
  198.    /* to close the circuit, we draw a line from the last point back to the first */
  199.    /* this usually is not necessary, but it prevents flood fill leaking */
  200.    if (!no_display)
  201.       draw_line(x, y, xstart, ystart);
  202.  
  203.    return length;      // return the length of the path
  204. }
  205.  
  206. // Draw a little car on the screen, at given position and orientation,
  207. // and with the given colors.  (to erase the car, call it with track_color)
  208. // returns a graphics error code, usually grOk, which is 0.
  209. void drawcar(double x,         // coordinates of center of car
  210.             double y,
  211.             double ang,       // orientation angle of car, wrt x-axis, radians
  212.             int nose,  // color of front portion
  213.             int tail)  // color of rear portion
  214. {
  215.    double xx, yy, endx, endy;
  216.    double sine, cosine, dx, dy;
  217.    int i;
  218.  
  219.    sine = sin(ang);    cosine = cos(ang);
  220.    xx = x + cosine * CARLEN/2 - sine * CARWID/2;    // left front corner coords
  221.    yy = y + cosine * CARWID/2 + sine * CARLEN/2;
  222.    x = xx;  y = yy;                                 // save the above values
  223.    dx = 0.3333 * CARWID * sine;
  224.    dy = -.3333 * CARWID * cosine;
  225.    // below we draw three parallel lines to form the body of the car:
  226.    set_color(tail);
  227.    for(i=0; i<=3; i++) {
  228.       endx = xx - CARLEN * cosine;
  229.       endy = yy - CARLEN * sine;
  230.       draw_line(xx, yy, endx, endy);
  231.       if(i == 3) break;
  232.       xx += dx;
  233.       yy += dy;
  234.    }
  235.    // now three short lines of the nose color to decorate the front:
  236.    set_color(nose);
  237.    xx = x;  yy = y;             // restore x and y to left front of car
  238.    for(i=0; i<=3; i++) {
  239.       endx = xx + CARWID * sine;
  240.       endy = yy - CARWID * cosine;
  241.       draw_line(xx, yy, endx, endy);
  242.       if(i == 3) break;
  243.       xx += dy;
  244.       yy -= dx;
  245.    }
  246. }
  247.  
  248. void lapper(int which, int lap)  // shows lap count on scoreboard,
  249. {                               // also returns lap+1 to advance the lap count
  250.    char string[] = "    ";      // and also increments done_count
  251.  
  252.    if(lap < 0)
  253.       lap = 0;
  254.  
  255.    set_fill_color(FIELD_COLOR);   // the green part is off the track
  256.    // This bar erases the previous lap count:
  257.    rectangle(SCORE_BOARD_X + 10*CHR_WID,
  258.              SCORE_BOARD_Y - which*CHR_HGT,
  259.              SCORE_BOARD_X + 13*CHR_WID,
  260.              SCORE_BOARD_Y - (which+.9)*CHR_HGT);
  261.  
  262.    set_color(TEXT_COLOR);          // now print text in black:
  263.    itoa(lap, string, 10);
  264.    text_output(SCORE_BOARD_X + 10 * CHR_WID,
  265.                SCORE_BOARD_Y - which * CHR_HGT, string);
  266. }
  267.  
  268. void border(void)
  269. {
  270.    set_color(RAIL_COLOR);
  271.    draw_line(0.0, 0.0, X_MAX, 0.0);
  272.    draw_line(X_MAX, 0.0, X_MAX, Y_MAX);
  273.    draw_line(X_MAX, Y_MAX, 0.0, Y_MAX);
  274.    draw_line(0.0, Y_MAX, 0.0, 0.0);
  275. }
  276.  
  277. // Initializes graphics system, draws track, fills in colored regions:
  278. void graph_setup(void)
  279. {
  280.    double alt_len;         // used in deciding the length of the track
  281.  
  282.    build_track();          // read track data and fill in trackou[], trackin[]
  283.    if(!no_display)  {
  284.       initialize_graphics();
  285.       /* instead of flood filling everything, we draw a rectangle */
  286.       set_fill_color(FIELD_COLOR);
  287.       rectangle(0.0, Y_MAX, X_MAX, 0.0);
  288.       border();               // draw border at screen boundary
  289.       // paint the whole screen green:
  290.       /*set_fill_color(FIELD_COLOR);*/
  291.       /*flood_fill(20.0, 20.0);*/
  292.    }
  293.    // draw outer track boundary:
  294.    length = drawpath(TRK_STRT_X, TRK_STRT_Y, 0, trackout);
  295.    finish_y_out = finish_y;                   // locate one end of finish line
  296.    // draw inner track boundary:
  297.    alt_len = drawpath(TRK_STRT_X, TRK_STRT_Y+width, 0, trackin);
  298.    if(alt_len < length)     // take length of shorter rail as track length
  299.       length = alt_len;
  300.    finish_y_in = finish_y;        // locate other end of finish line
  301.    if(no_display)
  302.       return;
  303.    // pave the track:
  304.    set_fill_color(TRACK_COLOR);
  305.    flood_fill(TRK_STRT_X, TRK_STRT_Y + width/2);     // the track
  306. }
  307.  
  308. void refresh_finish_line()
  309. {
  310.    set_color(TEXT_COLOR);
  311.    draw_line(finish_x, finish_y_out, finish_x, finish_y_in);
  312. }
  313.  
  314. // Put up the scoreboard:
  315. void scoreboard()
  316. {
  317.    int i;
  318.  
  319.    double XS = SCORE_BOARD_X;
  320.    double YS = SCORE_BOARD_Y;
  321.    char string[] = "12345678";
  322.    int kount;
  323.  
  324.    spacing = 1.15 * CHR_HGT;   // for the leader board only
  325.    // these rectangles are for the leader board car pictures:
  326.    kount = car_count < 5 ? car_count : 5;
  327.    // first erase the old board, if any:
  328.    set_fill_color(FIELD_COLOR);
  329.   rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
  330.              LDR_BRD_X + 19*CHR_WID, LDR_BRD_Y - (kount + .7) * spacing);
  331.     set_fill_color(TRACK_COLOR);   // rectangular background for car pictures:
  332.    rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
  333.              LDR_BRD_X -.5 * CARLEN, LDR_BRD_Y - (kount + .7) * spacing);
  334.    // these rectangles are for the scoreboard car pictures:
  335.    // first erase the old board, if any:
  336.    set_fill_color(FIELD_COLOR);
  337.    rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+13*CHR_WID,
  338.                                YS - car_count * CHR_HGT);
  339.    set_fill_color(TRACK_COLOR);
  340.    rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+.5*CARLEN,
  341.                                YS - car_count * CHR_HGT);
  342.    // draw the cars on the scoreboard:
  343.    for(i=0; i<car_count; i++) {
  344.       drawcar(XS-.1*CARLEN, YS - i * CHR_HGT - CARWID/2, 0,
  345.                               car_colors[i].nose, car_colors[i].tail);
  346.       set_color(TEXT_COLOR);
  347.       itoa(lap_count, string, 10);
  348.       text_output(XS+2*CHR_WID, YS - i * CHR_HGT, namptr[i]);
  349.       (void)lapper(i,-1);
  350.    }
  351.    text_output(XS - 13 * CHR_WID, SCORE_BOARD_Y + 1.5 * CHR_HGT,
  352.                                         "Race Length  Car  Driver  Laps");
  353.    text_output(LOTIX, LOTIY, "Length of track is      ft.");
  354.    itoa(int(length+.5), string, 10);
  355.    text_output(LOTIX + 16.5 * CHR_WID, LOTIY, string);
  356.    itoa(lap_count, string, 10);
  357.    text_output(SCORE_BOARD_X-10*CHR_WID, SCORE_BOARD_Y, string);
  358.    text_output(SCORE_BOARD_X-7*CHR_WID, SCORE_BOARD_Y, "laps");
  359.    text_output(LDR_BRD_X - CHR_WID, LDR_BRD_Y, "LEADERS:   max   avg");
  360.    text_output(LDR_BRD_X+11.5*CHR_WID, LDR_BRD_Y+CHR_HGT, "mph");
  361. }
  362.  
  363. // update the leader board when necessary:
  364. void leaders(int i)
  365. {
  366.    char string[] = "12345678";
  367.    double Y;
  368.  
  369.    Y = LDR_BRD_Y - spacing * (i + 1);
  370.  
  371.    // Erase old text:
  372.    set_fill_color(FIELD_COLOR);             // The infield color
  373.    rectangle(LDR_BRD_X, Y, LDR_BRD_X+19*CHR_WID, Y - CHR_HGT);
  374.  
  375.    set_color(TEXT_COLOR);
  376.    text_output(LDR_BRD_X, Y, namptr[order[i]]);
  377.    get_max_spd(order[i], string);                    // the maximum speed:
  378.    text_output(LDR_BRD_X+7.5*CHR_WID, Y, string);
  379.    get_avg_spd(order[i], string);                    // the average speed:
  380.    text_output(LDR_BRD_X+13.5*CHR_WID, Y, string);
  381.    drawcar(LDR_BRD_X-1.2*CARLEN, Y - CARWID/2, 0.0,
  382.                        car_colors[order[i]].nose, car_colors[order[i]].tail);
  383. }
  384.